﻿
// Snake1_1Dlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"
#include "Snake1_1.h"
#include "Snake1_1Dlg.h"
#include "afxdialogex.h"
#include "mmsystem.h"
#pragma comment(lib, "winmm.lib")
#include"GameRule.h"
#include"AboutGame.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CSnake11Dlg 对话框



CSnake11Dlg::CSnake11Dlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_SNAKE1_1_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON2);
}

void CSnake11Dlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CSnake11Dlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_TIMER()
	ON_WM_KEYDOWN()
	ON_COMMAND(ID_START, &CSnake11Dlg::OnStart)
	ON_COMMAND(ID_SPAUSE, &CSnake11Dlg::OnSpause)
	ON_COMMAND(ID_NEWGAME, &CSnake11Dlg::OnNewgame)
	ON_COMMAND(ID_MAN, &CSnake11Dlg::OnMan)
	ON_COMMAND(ID_ZHONG, &CSnake11Dlg::OnZhong)
	ON_COMMAND(ID_KUAI, &CSnake11Dlg::OnKuai)
	ON_COMMAND(ID_GAMEWAY, &CSnake11Dlg::OnGameway)
	ON_COMMAND(ID_ABOUTGAME, &CSnake11Dlg::OnAboutgame)
	ON_COMMAND(ID_PLAYMUSIC, &CSnake11Dlg::OnPlaymusic)
	ON_COMMAND(ID_STOPMUSIC, &CSnake11Dlg::OnStopmusic)
END_MESSAGE_MAP()


// CSnake11Dlg 消息处理程序

BOOL CSnake11Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	//设置应用程序图标
	m_hIcon=AfxGetApp()->LoadIconA(IDI_ICON1);
	SetIcon(m_hIcon, TRUE);
	//设置编辑框为不可编辑
	GetDlgItem(IDC_EDIT1)->EnableWindow(FALSE);
	GetDlgItem(IDC_EDIT2)->EnableWindow(FALSE);
	// 将“关于...”菜单项添加到系统菜单中。
	PlaySound(MAKEINTRESOURCE(IDR_WAVE1), AfxGetResourceHandle(), SND_ASYNC | SND_RESOURCE | SND_NODEFAULT);//单次播放
	m_start = false;
	m_pause = false;
	//初始化蛇身
	snake.n = 4;  snake.direction = 2;  snake.sorce = 0;  snake.MaxSorce = 0;
	snake.body[0].x = 2; snake.body[0].y = 5;
	snake.body[1].x = 2; snake.body[1].y = 4;
	snake.body[2].x = 2; snake.body[2].y = 3;
	snake.body[3].x = 2; snake.body[3].y = 2;
	//初始化食物
	time_t seed = time(NULL);
	srand(seed);
	do {
		Food.x = rand() % 25;
		Food.y = rand() % 35;
	} while (Isinsnake());

	//显示菜单
	CMenu m_Menu;
	m_Menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_Menu);

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CSnake11Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CSnake11Dlg::OnPaint()
{
	//设置游戏背景
	CDC* pDc = GetDC(); //返回GetDC()获取的CDC对象,后就可以对该对象进行操作
	CDC dc; //DC是一种包含设备信息的数据结构
	dc.CreateCompatibleDC(pDc); //创建一个内存设备上下文环境
	CBitmap bitmap; //创建位图对象
	bitmap.LoadBitmap(IDB_BITMAP1); //从资源文件中加载指定的位图资源
	dc.SelectObject(&bitmap); //把一个位图对象选入指定的设备描述表（dc)中。新的对象代替同一类型的老对象。
	for (int i = 0; i < 48; i++) {
		for (int j = 0; j < 28; j++) {
			pDc->StretchBlt(20 * i, 20 * j, 20, 20, &dc, 0, 0, 20, 20, SRCCOPY);//从源矩形中复制一个位图到目标矩形
		}
	} //用20x20像素的矩形去绘制一个长为48格，宽为28格的游戏界面
	bitmap.Detach();
	//自定义画笔颜色
	CPen pen(PS_SOLID, 3, RGB(211, 211, 211));
	CPen pen2(PS_SOLID, 3, RGB(255, 0, 0));
	CPen* oldpen = pDc->SelectObject(&pen);
	// 画下边框
	pDc->MoveTo(0, 560);
	pDc->LineTo(960, 560);
	pDc->SelectObject(&pen);
	// 画左边框	
	pDc->MoveTo(1, 0);
	pDc->LineTo(1, 560);
	//画上边框
	pDc->MoveTo(0, 1);
	pDc->LineTo(960, 1);
	pDc->SelectObject(&pen2);
	//画右边框
	pDc->MoveTo(960, 0);
	pDc->LineTo(960, 560);
	pDc->SelectObject(oldpen);

	//画蛇头
	bitmap.LoadBitmap(IDB_BITMAP2);
	dc.SelectObject(&bitmap);
	pDc->StretchBlt(20 + 20 * snake.body[0].y, 20 + 20 * snake.body[0].x, 20, 20, &dc, 0, 0, 20, 20, SRCCOPY);
	bitmap.Detach();
	//画蛇身
	bitmap.LoadBitmap(IDB_BITMAP3);
	dc.SelectObject(&bitmap);
	for (int i = 1; i < snake.n; i++)
		pDc->StretchBlt(20 + 20 * snake.body[i].y, 20 + 20 * snake.body[i].x, 20, 20, &dc, 0, 0, 20, 20, SRCCOPY);
	bitmap.Detach();
	//画食物
	bitmap.LoadBitmap(IDB_BITMAP4);
	dc.SelectObject(&bitmap);
	pDc->StretchBlt(20 + 20 * Food.y, 20 + 20 * Food.x, 20, 20, &dc, 0, 0, 20, 20, SRCCOPY);
	bitmap.Detach();
	//显示当前分数和历史最高分
	CString strsorce, strmax;
	strsorce.Format(TEXT("%d"), snake.sorce * 10);
	strmax.Format(TEXT("%d"), snake.MaxSorce * 10);
	GetDlgItem(IDC_EDIT1)->SetWindowText(strsorce);
	GetDlgItem(IDC_EDIT2)->SetWindowText(strmax);
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CSnake11Dlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



bool CSnake11Dlg::Isinsnake()
{
	// TODO: 在此处添加实现代码.
	for (int i = 0; i < snake.n; i++) {
		if (Food == snake.body[i])
			return true;
	}
	return false;
}


void CSnake11Dlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (snake.speed == 1)SetTimer(1, 250, NULL);
	if (snake.speed == 2)SetTimer(1, 110, NULL);
	if (snake.speed == 3)SetTimer(1, 80, NULL);//控制游戏速度，也就是游戏难度
	if (m_start && !m_pause)
	{
		CPoint temp;
		::CClientDC dc(this);
		CDC cdc;
		cdc.CreateCompatibleDC(&dc);
		CBitmap bitmap;
		switch (snake.direction) {
		case 1:
			temp = snake.ForsnakeUp();
			break;
		case 2:temp = snake.ForsnakeRight();
			break;
		case 3:temp = snake.ForsnakeDown();
			break;
		case 4:temp = snake.ForsnakeLeft();
			break;
		}
		if (IsGameOver()) {
			restart();
		}
		else
		{
			//覆盖蛇尾
			bitmap.LoadBitmap(IDB_BITMAP1);
			cdc.SelectObject(&bitmap);
			dc.StretchBlt(20 + 20 * temp.y, 20 + 20 * temp.x, 20, 20, &cdc, 0, 0, 20, 20, SRCCOPY);
			bitmap.Detach();


			//画蛇头
			bitmap.LoadBitmap(IDB_BITMAP2);
			cdc.SelectObject(&bitmap);
			dc.StretchBlt(20 + 20 * snake.body[0].y, 20 + 20 * snake.body[0].x, 20, 20, &cdc, 0, 0, 20, 20, SRCCOPY);
			bitmap.Detach();
			//画蛇身
			bitmap.LoadBitmap(IDB_BITMAP3);
			cdc.SelectObject(&bitmap);
			for (int i = 1; i < snake.n; i++)
				dc.StretchBlt(20 + 20 * snake.body[i].y, 20 + 20 * snake.body[i].x, 20, 20, &cdc, 0, 0, 20, 20, SRCCOPY);
			bitmap.Detach();
			if (Iseat()) {
				//更新分数
				snake.sorce++;
				CString strsorce;
				strsorce.Format(TEXT("%d"), snake.sorce * 10);
				GetDlgItem(IDC_EDIT1)->SetWindowText(strsorce);

				snake.n++;
				snake.body[snake.n - 1] = temp;
				dc.StretchBlt(20 + 20 * snake.body[snake.n - 1].y, 20 + 20 * snake.body[snake.n - 1].x, 20, 20, &cdc, 0, 0, 20, 20, SRCCOPY);
				bitmap.Detach();
				do {
					Food.x = rand() % 25;
					Food.y = rand() % 35;
				} while (Isinsnake());
				//画食物
				bitmap.LoadBitmap(IDB_BITMAP4);
				cdc.SelectObject(&bitmap);
				dc.StretchBlt(20 + 20 * Food.y, 20 + 20 * Food.x, 20, 20, &cdc, 0, 0, 20, 20, SRCCOPY);
				bitmap.Detach();
			}
		}

	}
	CDialogEx::OnTimer(nIDEvent);
}


void CSnake11Dlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (nChar == VK_UP && snake.direction != 1) {
		snake.direction = 1;
	}
	if (nChar == VK_RIGHT && snake.direction != 2) {
		snake.direction = 2;
	}
	if (nChar == VK_DOWN && snake.direction != 3) {
		snake.direction = 3;
	}
	if (nChar == VK_LEFT && snake.direction != 4) {
		snake.direction = 4;
	}
	CDialogEx::OnKeyDown(nChar, nRepCnt, nFlags);
}


bool CSnake11Dlg::IsGameOver()
{
	// TODO: 在此处添加实现代码.
	if (snake.body[0].x == -2 || snake.body[0].x == 27 || snake.body[0].y == -2 || snake.body[0].y == 47 || Istoach())
	{
		return true;
	}
	else
	{
		return false;
	}
	
}


void CSnake11Dlg::restart()
{
	// TODO: 在此处添加实现代码.
	//初始化蛇身
	snake.n = 4;  snake.direction = 2;
	snake.body[0].x = 2; snake.body[0].y = 5;
	snake.body[1].x = 2; snake.body[1].y = 4;
	snake.body[2].x = 2; snake.body[2].y = 3;
	snake.body[3].x = 2; snake.body[3].y = 2;
	//初始化食物
	time_t seed = time(NULL);
	srand(seed);
	do {
		Food.x = rand() % 25;
		Food.y = rand() % 35;
	} while (Isinsnake());
	
	m_start = false;
	m_pause = false;
	//更新历史最高分
	int tempmax = snake.MaxSorce * 10, tempsorce = snake.sorce * 10;
	if (snake.MaxSorce < snake.sorce)
		snake.MaxSorce = snake.sorce;
	snake.sorce = 0;
	OnPaint();
	CString string;
	string.Format(_T("\t本次得分:%d   \n\n\t历史最高分:%d"), tempsorce, tempmax); //将变量组装到字符串中
	MessageBox(string, _T("游戏结束！！"), 1);
}


void CSnake11Dlg::OnStart()
{
	// TODO: 在此添加命令处理程序代码
	this->m_start = true;
	this->m_pause = false;


	if (snake.speed == 1)SetTimer(1, 250, NULL);
	if (snake.speed == 2)SetTimer(1, 110, NULL);
	if (snake.speed == 3)SetTimer(1, 80, NULL);

}


void CSnake11Dlg::OnSpause()
{
	// TODO: 在此添加命令处理程序代码
	static int t = 1;
	if (t & 1) {
		this->m_pause = true;
	}
	else {
		this->m_pause = false;
	}
	t++;
}


void CSnake11Dlg::OnNewgame()
{
	// TODO: 在此添加命令处理程序代码
	//初始化蛇身
	snake.n = 4;  snake.direction = 2;
	snake.body[0].x = 2; snake.body[0].y = 5;
	snake.body[1].x = 2; snake.body[1].y = 4;
	snake.body[2].x = 2; snake.body[2].y = 3;
	snake.body[3].x = 2; snake.body[3].y = 2;
	//初始化食物
	unsigned seed = time(NULL);
	srand(seed);
	do {
		Food.x = rand() % 25;
		Food.y = rand() % 35;
	} while (Isinsnake());
	
	m_start = false;
	m_pause = false;
	//更新历史最高分
	int tempmax = snake.MaxSorce * 10, tempsorce = snake.sorce * 10;
	if (snake.MaxSorce < snake.sorce)
		snake.MaxSorce = snake.sorce;
	snake.sorce = 0;
	OnPaint();

}


void CSnake11Dlg::OnMan()
{
	// TODO: 在此添加命令处理程序代码
	snake.speed = 1;
}


void CSnake11Dlg::OnZhong()
{
	// TODO: 在此添加命令处理程序代码
	snake.speed = 2;
}


void CSnake11Dlg::OnKuai()
{
	// TODO: 在此添加命令处理程序代码
	snake.speed = 3;
}


bool CSnake11Dlg::Iseat()
{
	// TODO: 在此处添加实现代码.
	if (snake.body[0] == Food)
		return true;
	return false;
}


bool CSnake11Dlg::Istoach()
{
	// TODO: 在此处添加实现代码.
	for (int i = 1; i < snake.n; i++)
		if (snake.body[0] == snake.body[i])
			return true;
	return false;
}


BOOL CSnake11Dlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
	{
		HACCEL hAccel = hAccTable;
		if (hAccel && ::TranslateAccelerator(m_hWnd, hAccel, pMsg))
			return TRUE;
	}
	// TODO:  在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)
	{
		if (pMsg->wParam == VK_UP && snake.direction != 3)
		{
			snake.direction = 1;
		}
		if (pMsg->wParam == VK_RIGHT && snake.direction != 4)
		{
			snake.direction = 2;
		}
		if (pMsg->wParam == VK_DOWN && snake.direction != 1)
		{
			snake.direction = 3;
		}
		if (pMsg->wParam == VK_LEFT && snake.direction != 2)
		{
			snake.direction = 4;
		}
	}
	return CDialogEx::PreTranslateMessage(pMsg);
}


void CSnake11Dlg::OnGameway()
{
	// TODO: 在此添加命令处理程序代码
	GameRule dlg;
	dlg.DoModal();
}


void CSnake11Dlg::OnAboutgame()
{
	// TODO: 在此添加命令处理程序代码
	AboutGame dlg;
	dlg.DoModal();
}


void CSnake11Dlg::OnPlaymusic()
{
	// TODO: 在此添加命令处理程序代码
	PlaySound(MAKEINTRESOURCE(IDR_WAVE1), AfxGetResourceHandle(), SND_ASYNC | SND_RESOURCE | SND_NODEFAULT);//单次播放
}


void CSnake11Dlg::OnStopmusic()
{
	// TODO: 在此添加命令处理程序代码
	PlaySound(0, NULL, 0);
}
